
/* GCSx
** FRONTEND.CPP
**
** Front-end module- leads to game, editor, configuration, etc.
*/

/*****************************************************************************
** Copyright (C) 2003-2006 Janson
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** 
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
*****************************************************************************/

#include "all.h"

int gameMode = MODE_FRONTEND;
// overlay mode- game accepts keyboard input
// desktop MAY be overlaid over game in a translucent state
int gameOverlayMode = 0;

int getProgramMode() { start_func
    return gameMode;
}

void exitGameOverlayMode() { start_func
    if (gameOverlayMode) {
        gameOverlayMode = 0;
        SDL_EnableUNICODE(1);
        SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
        setScreenGLAlpha(config->readNum(FRONTEND_ACTIVE_ALPHA));
        desktop->setBackgroundAlpha(config->readNum(FRONTEND_ACTIVE_BKALPHA));
    }
}

void enterGameOverlayMode() { start_func
    if (gameMode == MODE_GAMEPLAY) {
        gameOverlayMode = 1;
        SDL_EnableKeyRepeat(0, 0);
        SDL_EnableUNICODE(0);
        setScreenGLAlpha(config->readNum(FRONTEND_INACTIVE_ALPHA));
        desktop->setBackgroundAlpha(config->readNum(FRONTEND_INACTIVE_BKALPHA));
    }
}

void exitGameMode() { start_func
    if (gameMode == MODE_GAMEPLAY) {
        desktop->setGameLoop(NULL);
        gcsxEndgame();
        gameMode = MODE_FRONTEND;
    }
    exitGameOverlayMode();
}

void enterGameMode() { start_func
    // (presumes you loaded a game!)
    desktop->setGameLoop(gcsxGameloopGui);
    gameMode = MODE_GAMEPLAY;
    setScreenGLAlpha(config->readNum(FRONTEND_ACTIVE_ALPHA));
    desktop->setBackgroundAlpha(config->readNum(FRONTEND_ACTIVE_BKALPHA));
}

void initDefaultVideo() { start_func
    // Initialize default video mode
    int x = config->readNum(VIDEO_X);
    int y = config->readNum(VIDEO_Y);
    int bpp = config->readNum(VIDEO_BPP);
    if (x < 320) x = 320;
    if (y < 240) y = 240;
    if ((bpp != 15) && (bpp != 16) && (bpp != 24) && (bpp != 32)) bpp = -1;
    selectVideoMode(x, y, bpp, config->readNum(VIDEO_FULLSCREEN), config->readNum(VIDEO_RESIZABLE));
}

// Menu tree for front end
PopupMenu::PopupGen frontEndMenuTree[] = {
    { MENU_SUB, "\tFile", 0 },
        { FILE_OPENEXIST, "\tLoad world...", 0 },
        { FILE_RETURNGAME, "\tReturn to game", 1 },
        { FILE_CLOSEGAME, "\tClose game", 1 },
        { MENU_SEP, NULL, 0 },
        { FILE_EDITOR, "\tEditor", 0 },
        { MENU_SEP, NULL, 0 },
        { FILE_EXIT, "E\txit", 0 },
        { 0, NULL, 0 },
    { MENU_SUB, "\tDebug", 0 },
        { VIEW_CONSOLE, "\tConsole", 1 },
        { 0, NULL, 0 },
    { MENU_SUB, "\tConfig", 0 },
        { CONFIG_RESOLUTION, "\tResolution...", 1 },
        { 0, NULL, 0 },
    /* Removed (@TODO:)
    { MENU_SUB, "\tHelp", 0 },
        { MENU_HELP_INDEX, "\tIndex", 0 },
        { 0, NULL, 0 },
    */
    { 0, NULL, 0 }
};

// Menu handler for front-end
Window::CommandSupport frontEndCommandSupport(int code) { start_func
    switch (code) {
        case VIEW_CONSOLE:
            return (Window::CommandSupport)((debugWindow()->isOpen() ? Window::COMMAND_SELECTED : 0) | Window::COMMAND_CHECKBOX | Window::COMMAND_ENABLE);

        case CONFIG_RESOLUTION:
            return gameMode == MODE_GAMEPLAY ? Window::COMMAND_DISABLE : Window::COMMAND_ENABLE;

        case FILE_RETURNGAME:
        case FILE_CLOSEGAME:
            return gameMode == MODE_GAMEPLAY ? Window::COMMAND_ENABLE : Window::COMMAND_DISABLE;
    }

    return Window::COMMAND_HIDE;
}

// Command handler for front-end
int frontEndHandleGlobalEvents(const SDL_Event* event) { start_func
    string myFile;

    switch (event->type) {
        case SDL_SYSKEY:
            // These work even if shortcuts have been removed
            if ((event->key.keysym.sym == SDLK_ESCAPE) ||
                (event->key.keysym.sym == SDLK_F12)) {
                if (gameMode == MODE_GAMEPLAY) {
                    if (desktop->findWindow(Window::WINDOW_FRAME, 0)) {
                        enterGameOverlayMode();
                        desktop->bringToTop(NULL);
                    }
                    else {
                        desktop->broadcastEvent(SDL_SPECIAL, SDL_QUITTOGAME);
                    }
                }
            }
            break;

        case SDL_SPECIAL:
            if (event->user.code == SDL_IDLETIMEOUTSHORT) {
                config->performSave();
                return 1;
            }
            
            if (event->user.code == SDL_CLOSEGAME) {
                exitGameMode();
            }
            
            if ((event->user.code == SDL_DESKTOPACTIVE) && (gameMode == MODE_GAMEPLAY)) {
                // If windows, go into 'overlay' mode; otherwise just return to game
                if (desktop->findWindow(Window::WINDOW_FRAME, 0)) {
                    enterGameOverlayMode();
                }
                else {
                    desktop->broadcastEvent(SDL_SPECIAL, SDL_QUITTOGAME);
                }
            }
            
            if ((event->user.code == SDL_DESKTOPINACTIVE) && (gameMode == MODE_GAMEPLAY)) {
                // Exit 'overlay' mode
                exitGameOverlayMode();
            }
            break;
            
        case SDL_COMMAND:
            switch (event->user.code) {
                case FILE_RETURNGAME:
                    if (gameMode == MODE_GAMEPLAY) {
                        if (desktop->findWindow(Window::WINDOW_FRAME, 0)) {
                            enterGameOverlayMode();
                            desktop->bringToTop(NULL);
                        }
                        else {
                            desktop->broadcastEvent(SDL_SPECIAL, SDL_QUITTOGAME);
                        }
                    }
                    return 1;

                case FILE_CLOSEGAME:
                    exitGameMode();
                    return 1;

                case FILE_EDITOR:
                    desktop->broadcastEvent(SDL_SPECIAL, SDL_QUITTOEDITOR);
                    return 1;
            
                case FILE_OPENEXIST:
                    try {
                        if (fileOpen(FILETYPE_WORLD, 0, myFile)) {
                            exitGameMode();
                            gcsxGameplay(myFile);
                            // Warning about F12
                            if (config->readNum(WARN_GAMEMENU)) {
                                if (guiRemindBox("During gameplay, press F12 to toggle the menu/desktop.", warnTitleReminder)) {
                                    config->write(WARN_GAMEMENU, 0);
                                }
                            }
                            enterGameMode();
                            desktop->broadcastEvent(SDL_SPECIAL, SDL_QUITTOGAME);
                        }
                    }
                    catch (FileException& e) {
                        guiErrorBox(string(e.details), errorTitleFile);
                    }
                    return 1;
                    
                case FILE_EXIT:
                    desktop->broadcastEvent(SDL_QUIT, 0);
                    return 1;
                    
                case CONFIG_RESOLUTION:
                    if (gameMode != MODE_GAMEPLAY)
                        ResolutionDialog::create()->chooseResolution();
                    return 1;
                    
                case VIEW_CONSOLE:
                    if (debugWindow()->isOpen()) {
                        // Attempting to access console in overlay mode just exits overlay mode
                        if (gameOverlayMode) {
                            desktop->bringToTop(dynamic_cast<Window*>(debugWindow()->getParent()));
                        }
                        else {
                            debugWindow()->closeWindow();
                            
                            // If closing console during game, return to game
                            if (gameMode == MODE_GAMEPLAY) {
                                desktop->broadcastEvent(SDL_SPECIAL, SDL_QUITTOGAME);
                            }
                        }
                    }
                    else {
                        debugWindow()->runWindowed();
                    }
                    return 1;

                case MENU_HELP_INDEX:
                    // @TODO: Help system
                    return 1;
            }
            break;
    }
    
    return 0;
}

void gcsxFrontEnd() { start_func
    PopupMenu* frontEndMenu = NULL;
    int quitType = 0;
    SDL_Surface* bk;

    do {
        gameMode = MODE_FRONTEND;
        gameOverlayMode = 0;

        try {
            // Until we enter a game module, we need unicode translation and repeating keys
            SDL_EnableUNICODE(1);
            SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
        
            // Our event handlers
            desktop->setEventHandler(frontEndHandleGlobalEvents);
            desktop->setSupportsHandler(frontEndCommandSupport);
    
            // Set up our menus
            frontEndMenu = PopupMenu::compileMenu(frontEndMenuTree, 1);
            frontEndMenu->menubar(1);
            
            // Background (error results in quietly having no bk image)
            string bkFile;
            createFilename(resourceDir->c_str(), FILENAME_BKFRONT, bkFile);
            bk = IMG_Load(bkFile.c_str());
            desktop->setBackground(bk, COLOR_FRONTDESKTOP);
            
            SDL_WM_SetCaption(PRODUCT_NAME, PRODUCT_NAME);

            // Enter main event loop
            do {
                quitType = desktop->eventLoop();
                
                if (quitType == SDL_QUITTOGAME) {
                    // Enter pure-game mode
                    enterGameOverlayMode();
                    int result;
                    do {
                        result = gcsxGameloop();
                    } while (!result);
                    exitGameOverlayMode();
                    clearEvents();
                    
                    // Exit?
                    if (result == GAME_EXIT) {
                        exitGameMode();
                    }
                    
                    if (result == GAME_CONSOLE) {
                        if (!debugWindow()->isOpen()) {
                            debugWindow()->runWindowed();
                        }
                    }
                    
                    // Either way, loop back to main loop and make menu active
                    desktop->bringToTop(desktop->findWindow(Window::WINDOW_MENUBAR, 0), 1);
                }
            } while (quitType == SDL_QUITTOGAME);
            
            exitGameMode();
            
            // Close all windows
            desktop->closeAllWindows();
            
            // Cleanup
            // @TODO: Standardize 3 sets of cleanup into one (don't run beginExitStage() here!)
            desktop->setBackground(NULL, COLOR_FRONTDESKTOP);
            SDL_FreeSurface(bk);
            delete frontEndMenu;
            frontEndMenu = NULL;
            desktop->setSupportsHandler(NULL);
            desktop->setEventHandler(NULL);
            desktop->initEventCleanup();
            SDL_EnableKeyRepeat(0, 0);
            SDL_EnableUNICODE(0);
            clearEvents();
        }
        // Any exceptions
        catch (...) {
            try {
                beginExitStage();
                
                // Cleanup
                desktop->deleteAllWindows();
                desktop->setBackground(NULL, COLOR_FRONTDESKTOP);
                SDL_FreeSurface(bk);
                delete frontEndMenu;
                desktop->setSupportsHandler(NULL);
                desktop->setEventHandler(NULL);
                desktop->initEventCleanup();
                SDL_EnableKeyRepeat(0, 0);
                SDL_EnableUNICODE(0);
                clearEvents();
            }
            catch (...) {
            }
            // Pass it on
            throw;
        }

        // Enter editor? (and then loops for more)
        if (quitType == SDL_QUITTOEDITOR) {
            gameMode = MODE_EDITOR;
            // Shall we return to front end?
            if (!gcsxEditor()) quitType = 0;
            gameMode = MODE_FRONTEND;
        }
    } while (quitType > 1);

    // Save configuration last, only if no exceptions
    // (if exceptions, it may be a faulty configuration change)
    config->performSave();
}

